//
// Copyright (c) 2004-2006 BroadVision, Inc. All rights reserved.
//
// This software is copyrighted.  Under the copyright laws, this software
// may not be copied, in whole or in part, without prior written consent
// of BroadVision, Inc. or its assignees.  This software is provided under
// the terms of a license between BroadVision and the recipient, and its
// use is subject to the terms of that license.
//
// This software may be protected by one or more U.S. and International
// patents.  Certain applications of BroadVision One-To-One software are
// covered by U.S. patent 5,710,887.
//
// TRADEMARKS: BroadVision and BroadVision One-To-One are registered
// trademarks of BroadVision, Inc., in the United States and the European
// Community, and are trademarks of BroadVision, Inc., in other
// countries.  The BroadVision logo, is a trademark of BroadVision, Inc.,
// in the United States and other countries. Additionally, IONA and Orbix
// are trademarks of IONA Technologies, Ltd.  RSA, MD5, and RC2 are
// trademarks of RSA Data Security, Inc.
//

package com.broadvision.manage.common.tools.action.common;

import java.util.List;
import java.util.ArrayList;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.Globals;
import com.broadvision.system.accesscontrol.client.GenericRoleDB;
import com.broadvision.system.accesscontrol.client.UserRole;
import com.broadvision.system.accesscontrol.client.ServiceObjectInfo;
import com.broadvision.system.accesscontrol.utils.ServiceRoleFilter;
import com.broadvision.system.accesscontrol.exceptions.AccessControlException;
import com.broadvision.visitor.client.Visitor;
import com.broadvision.web.action.Constants;
import com.broadvision.web.action.PathFilterSystem;
import com.broadvision.web.servlet.SessionVisitor;
import com.broadvision.manage.common.tools.action.RoleResolver;
import com.broadvision.manage.tools.action.BaseAction;
import com.broadvision.manage.tools.ToolsLog;

/**
 * Displays the home page.
 */
public class HomeAction extends BaseAction {

  /**
   *
   */
  public final static String HOME_PAGE_KEY = HomeAction.class.getName() + ".HOME_PAGE_KEY";

  /**
   * Implements the action for displaying the home page.
   * <p> <p>
   * @param mapping <code>ActionMapping</code> object used to select this instance
   * @param form Optional <code>ActionForm</code> bean for this request (if any)
   * @param request <code>HttpServletRequest</code> object to process
   * @param response <code>HttpServletResponse</code> object to process
   * <p> <p>
   * @return <code>ActionForward</code> instance describing where and how
   * control should be forwarded, or null if the response has already been completed
   * <p> <p>
   * @throws Exception if an error occurs
   */
  public ActionForward processExecute(ActionMapping mapping,
                                      ActionForm form,
                                      HttpServletRequest request,
                                      HttpServletResponse response)
                               throws Exception {
    int serviceId = getServiceId(request);
    HttpSession session = request.getSession();
    SessionVisitor sessionVisitor = SessionVisitor.getInstance(session);
    Visitor visitor = sessionVisitor.getVisitor();
    String homePageKey = HOME_PAGE_KEY + visitor.getId();

    String homePage = (String) session.getAttribute(homePageKey); 

    boolean cache = this.cache();
    if (!cache || (null == homePage)) {
      homePage = getHomePage(request, mapping, serviceId, visitor);

      if (cache) {
        session.setAttribute(homePageKey, homePage);
      }
    }

    if (null != homePage) {
      return new ActionForward(homePage);
    }

    ActionForward none = mapping.findForward("none");
    if (null != none) {
      request.setAttribute(Globals.ERROR_KEY, "mc.common.login.permission");
      return none;
    }

    return mapping.findForward("success");
  }

  /**
   * Get the visitor's home page based on their role(s).
   * <p> <p>
   * @param request <code>HttpServletRequest</code>
   * @param mapping <code>ActionMapping</code>
   * @param serviceId
   * @param visitor <code>Visitor</code>
   */
  protected String getHomePage(HttpServletRequest request,
                               ActionMapping mapping,
                               int serviceId,
                               Visitor visitor)
                        throws Exception {
    String homePage = null;
    PathFilterSystem filter = (PathFilterSystem) getServlet().
      getServletContext().getAttribute(Constants.PATHFILTERSYSTEM_KEY);
    if (null != filter) {
      String[] roles = getRoles(serviceId, visitor, request);
      homePage = filter.getPath(request, mapping, roles);
    }

    return homePage;
  }

  /**
   *
   * <p> <p>
   * @param serviceId
   * @param visitor <code>Visitor</code>
   * @param request <code>HttpServletRequest</code>
   */
  protected String[] getRoles(int serviceId, Visitor visitor, HttpServletRequest request) {
    List list = new ArrayList();

    List resolvedRoles = getResolvedRoles(serviceId, visitor, request);
    list.addAll(resolvedRoles);

    List grantedRoles = getGrantedRoles(serviceId, visitor, request);
    list.addAll(grantedRoles);

    String[] roles = new String[list.size()];
    for (int index = 0; index < list.size(); index++) {
      roles[index] = (String) list.get(index);
    }

    return roles;
  }

  /**
   *
   * <p> <p>
   * @param serviceId
   * @param visitor <code>Visitor</code>
   * @param request <code>HttpServletRequest</code>
   */
  protected List getResolvedRoles(int serviceId, Visitor visitor, HttpServletRequest request) {
    List list = new ArrayList();
    RoleResolver roleResolver = new RoleResolver();
    String[] resolvedRoles = roleResolver.getRoles();
    for (int index = 0; index < resolvedRoles.length; index++) {
      String role = resolvedRoles[index];
      try {
        if (roleResolver.isUserInRole(visitor, role, request)) {
          list.add(role);
        }
      }
      catch (Exception e) {
        ToolsLog.error(this.getClass(), "getResolvedRoles",
                       "RoleResolver.isUserInRole() failed: " + role);
      }
    }
    return list;
  }

  /**
   *
   * <p> <p>
   * @param serviceId
   * @param visitor <code>Visitor</code>
   * @param request <code>HttpServletRequest</code>
   */
  protected List getGrantedRoles(int serviceId, Visitor visitor, HttpServletRequest request) {
    ServiceObjectInfo serviceObjectInfo = new ServiceObjectInfo(serviceId);
    List list = new ArrayList();
    GenericRoleDB genericRoleDB = new GenericRoleDB();
    try {
      List grantedRoles = genericRoleDB.getGrantedRolesForPrincipal(visitor);
      for (int index = 0; index < grantedRoles.size(); index++) {
        Object object = grantedRoles.get(index);
        if (object instanceof UserRole) {
          UserRole userRole = (UserRole) object;
          boolean isServiceRole = ServiceRoleFilter.isServiceRole(userRole);
          if (isServiceRole) {
            boolean isUserPermittedServiceRole =
              ServiceRoleFilter.isUserPermittedServiceRole(visitor,
                                                           userRole,
                                                           serviceObjectInfo);
            if (isUserPermittedServiceRole) {
              list.add(userRole.getName());
            }
          }
          else {
            list.add(userRole.getName());
          }
        }
      }
    }
    catch (AccessControlException e) {
      ToolsLog.error(this.getClass(), "getGrantedRoles",
                     "GenericeRoleDB.getGrantedRolesForPrincipal() failed");
    }
    return list;
  }

  /**
   *
   */
  protected boolean cache() {
    return true;
  }
}
